package com.dh.convert.rule.function;

import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorJavaType;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorRuntimeJavaType;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.EnumSet;
import java.util.Map;
import java.util.Objects;

/**
 * @author huwenxuan
 * @date 2018/11/8
 */
public class NewEnumFunction extends AbstractFunction {

	private static Map<String,Object> ENUM_CACHE = Maps.newConcurrentMap();

	@Override
	public String getName() {
		return "newEnum";
	}

	/**
	 * 枚举转换
	 *
	 * @param env
	 * @param arg1
	 *            数据
	 * @param arg2
	 *            目标枚举
	 * @param arg3
	 *            源字段
	 * @param arg4
	 *            目标字段
	 * @return
	 */
	@Override
	public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2,AviatorObject arg3) {
		Object o = arg1.getValue(env);
		Object result = null;
		String className = getField(arg2, env);
		String srcField = getField(arg3, env);

		if (Objects.isNull(o) || StringUtils.isAnyBlank(className, srcField)) {
			throw new RuntimeException("请检查枚举配置是否正确！");
		}

		String cacheName = Joiner.on("-").join(className, srcField, o);

		try {
			if (null == (result = ENUM_CACHE.get(cacheName))) {
				Class enumClazz;
				try {
					enumClazz = Class.forName(className);
				} catch (ClassNotFoundException e) {
					throw new RuntimeException(String.format("无法识别类型:%s", className), e);
				}

				EnumSet enumSet = EnumSet.allOf(enumClazz);
				for (Object enum0 : enumSet) {
					Field sf = enum0.getClass().getDeclaredField(srcField);
					if (null != sf) {
						sf.setAccessible(true);
						if (String.valueOf(o).equals(String.valueOf(sf.get(enum0)))) {
							result = enum0;
							ENUM_CACHE.put(cacheName, enum0);
							break;
						}
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(String.format("格转枚举转换%s异常！%s", cacheName, e.getMessage()));
		}

		if (null == result) {
			throw new IllegalArgumentException(String.format("参数%s不在枚举域内", getField(arg3, env)));
		}

		return new AviatorRuntimeJavaType(result);
	}

	/**
	 * 根据aviatorObject获取目标字符串
	 *
	 * @param aviatorObject
	 * @param env
	 * @return
	 */
	private String getField(AviatorObject aviatorObject, Map<String, Object> env) {
		String targetField;
		if (aviatorObject instanceof AviatorJavaType) {
			targetField = ((AviatorJavaType) aviatorObject).getName();
		} else {
			targetField = FunctionUtils.getStringValue(aviatorObject, env);
		}

		return targetField;
	}
}
